package com.iwdnb.gkgz.common.utils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.iwdnb.bmnf.common.utils.BeanConvertUtils;
import com.iwdnb.gkgz.common.enums.RangeTypeEnums;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.model.dto.StockRangeApproximateData;
import com.iwdnb.gkgz.common.model.dto.StockRangeDTO;
import com.iwdnb.gkgz.common.model.dto.StockRangeScopeDTO;
import com.iwdnb.gkgz.common.model.dto.StockRangeStatistic;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 股票均价计算
 */
@Slf4j
public class StockRangeUtils {

    private static final BigDecimal MIN_RANGE_PRICE_SCOPE = new BigDecimal(25);
    private static final BigDecimal HIGH_SCOPE = new BigDecimal(3);
    private static final BigDecimal LOW_SCOPE = new BigDecimal(-5);

    public static List<StockRangeDTO> calculateStockRange(List<StockDayData> stockDayDataList) {
        return calculateStockRange(stockDayDataList, MIN_RANGE_PRICE_SCOPE);
    }

    /**
     * 计算股票波段
     *
     * @param stockDayDataList
     * @return
     */
    public static List<StockRangeDTO> calculateStockRange(List<StockDayData> stockDayDataList,
        BigDecimal rangePriceScope) {
        List<StockRangeDTO> result = new ArrayList<>();
        StockDayData startData = stockDayDataList.get(0);
        int size = stockDayDataList.size() >= 200 ? 200 : stockDayDataList.size();
        StockDirectionData stockDirectionData = getDirectionData(startData, stockDayDataList.subList(0, size),
            rangePriceScope);
        StockDayData changeDayData = BeanConvertUtils.convert(stockDirectionData.getStockDayData(), StockDayData.class);
        String direction = stockDirectionData.getDirection();
        int startIndex = 0;
        for (int i = 1; i < stockDayDataList.size(); i++) {
            StockDayData data = stockDayDataList.get(i);
            if (!StringUtils.equals(changeDayData.getDate(), data.getDate())) {
                continue;
            }
            int end = i + 200 < stockDayDataList.size() ? i + 200 : stockDayDataList.size() - 1;
            stockDirectionData = getDirectionData(changeDayData, stockDayDataList.subList(i, end), rangePriceScope);
            if (Objects.isNull(stockDirectionData)) {
                break;
            }
            //log.info("calculateStockRange date:{},directDate:{},direction:{}", data.getDate(),
            //    stockDirectionData.getStockDayData().getDate(), stockDirectionData.getDirection());
            if (StringUtils.equals(direction, stockDirectionData.getDirection())) {
                //把数据往后跳到对应股价数据
                changeDayData = BeanConvertUtils.convert(stockDirectionData.getStockDayData(), StockDayData.class);
                continue;
            } else {
                //方向不一致，是拐点，持久化顶底部节点数据,找到这一段中的顶点或者低点
                int index = i + stockDirectionData.getMiddleIndex();
                //getChangeIndex(direction, stockDayDataList, startIndex,
                //i + stockDirectionData.getIndex());
                StockDayData stockDayData = stockDayDataList.get(index);
                StockRangeDTO stockRangeDTO = new StockRangeDTO();
                stockRangeDTO.setRangeType(direction);
                stockRangeDTO.setCode(stockRangeDTO.getCode());
                if (direction.equals(RangeTypeEnums.UP.getCode())) {
                    //BigDecimal lowPrice = BigDecimalUtils.isGe(startData.getRate(), BigDecimal.ZERO)
                    //    ? startData.getOpenPrice() : startData.getClosePrice();
                    //BigDecimal highPrice = BigDecimalUtils.isGe(stockDayData.getRate(), BigDecimal.ZERO)
                    //    ? stockDayData.getClosePrice() : stockDayData.getOpenPrice();
                    BigDecimal lowPrice = startData.getMinPrice();
                    BigDecimal highPrice = stockDayData.getMaxPrice();
                    stockRangeDTO.setBeginDate(startData.getDate());
                    stockRangeDTO.setLowPrice(lowPrice);
                    stockRangeDTO.setEndDate(stockDayData.getDate());
                    stockRangeDTO.setHighPrice(highPrice);
                    stockRangeDTO.setRate(BigDecimalUtils.subStractAndDividePrecent(highPrice, lowPrice));
                } else {
                    //BigDecimal highPrice = BigDecimalUtils.isGe(startData.getRate(), BigDecimal.ZERO)
                    //    ? startData.getClosePrice() : startData.getOpenPrice();
                    //BigDecimal lowPrice = BigDecimalUtils.isGe(stockDayData.getRate(), BigDecimal.ZERO)
                    //    ? stockDayData.getOpenPrice() : stockDayData.getClosePrice();
                    BigDecimal highPrice = startData.getMaxPrice();
                    BigDecimal lowPrice = stockDayData.getMinPrice();
                    //如果下影线大于4个点,最小价设为下影线的一半
                    BigDecimal bodyLowPrice = BigDecimalUtils.isGe(stockDayData.getRate(), BigDecimal.ZERO)
                        ? stockDayData.getOpenPrice() : stockDayData.getClosePrice();
                    BigDecimal downLineRate = BigDecimalUtils.subStractAndDividePrecent(bodyLowPrice, lowPrice);
                    if (BigDecimalUtils.isGe(downLineRate, new BigDecimal(3))) {
                        lowPrice = BigDecimalUtils.divide(lowPrice.add(bodyLowPrice), new BigDecimal(2));
                    }
                    stockRangeDTO.setBeginDate(startData.getDate());
                    stockRangeDTO.setHighPrice(highPrice);
                    stockRangeDTO.setEndDate(stockDayData.getDate());
                    stockRangeDTO.setLowPrice(lowPrice);
                    stockRangeDTO.setRate(BigDecimalUtils.subStractAndDividePrecent(lowPrice, highPrice));
                }
                //设置区间最高或者最低价
                stockRangeDTO.setEndLimitPrice(
                    direction.equals(RangeTypeEnums.UP.getCode()) ? stockDayData.getMaxPrice()
                        : stockDayData.getMinPrice());

                result.add(stockRangeDTO);
                startIndex = index;
                changeDayData = BeanConvertUtils.convert(stockDayData, StockDayData.class);
                direction = stockDirectionData.getDirection();
                startData = BeanConvertUtils.convert(stockDayData, StockDayData.class);
                if (index <= i && i < stockDayDataList.size() - 1) {
                    changeDayData = BeanConvertUtils.convert(stockDayDataList.get(i + 1), StockDayData.class);

                }
            }
        }
        //添加最近的波段
        //addLatestRange(result, stockDayDataList);
        //calculateRangeHoldDay(result, stockDayDataList);
        return result;
    }

    public static StockRangeScopeDTO getRangeScopeByDateRange(List<StockRangeDTO> stockRangeDTOList,
        String endDateStr) {
        String beginDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.parseDate(endDateStr), -450));
        return getRangeScopeByDateRange(stockRangeDTOList, beginDate, endDateStr);
    }

    public static StockRangeScopeDTO getRangeScopeByDateRange(List<StockRangeDTO> stockRangeDTOList,
        String beginDateStr, String endDateStr) {
        Date begin = DateUtil.parseDate(beginDateStr);
        Date end = DateUtil.parseDate(endDateStr);
        String lowDate = null;
        String highDate = null;
        BigDecimal highPrice = new BigDecimal(0);
        BigDecimal lowPrice = new BigDecimal(100000);
        for (StockRangeDTO stockRangeDTO : stockRangeDTOList) {
            Date beginDate = DateUtil.parseDate(stockRangeDTO.getBeginDate());
            Date endDate = DateUtil.parseDate(stockRangeDTO.getEndDate());
            // 如果一个时间段的开始时间晚于另一个时间段的结束时间，则两者无交集
            if (endDate.before(begin) || end.before(beginDate)) {
                continue;
            }
            BigDecimal price = stockRangeDTO.getLowPrice();
            if (BigDecimalUtils.isLt(price, lowPrice)) {
                lowPrice = price;
                lowDate = RangeTypeEnums.UP.equalsCode(stockRangeDTO.getRangeType()) ? stockRangeDTO.getBeginDate()
                    : stockRangeDTO.getEndDate();
            }
            if (BigDecimalUtils.isGt(price, highPrice)) {
                highPrice = price;
                highDate = RangeTypeEnums.UP.equalsCode(stockRangeDTO.getRangeType()) ? stockRangeDTO.getEndDate()
                    : stockRangeDTO.getBeginDate();
            }

        }
        StockRangeScopeDTO rangeScopeDTO = new StockRangeScopeDTO();
        rangeScopeDTO.setLowPrice(lowPrice);
        rangeScopeDTO.setHighPrice(highPrice);
        rangeScopeDTO.setHighDate(highDate);
        rangeScopeDTO.setLowDate(lowDate);
        return rangeScopeDTO;
    }

    /**
     * 获取匹配的低价波段
     *
     * @param stockDayData
     * @param stockRangeDTOList
     * @return
     */
    public static StockRangeDTO getMatchLowRangeByDateRange(StockDayData stockDayData,
        List<StockRangeDTO> stockRangeDTOList) {
        return getMatchLowRangeByDateRange(stockDayData, stockRangeDTOList, HIGH_SCOPE, LOW_SCOPE);
    }

    /**
     * 获取匹配的低价波段
     *
     * @param stockDayData
     * @param stockRangeDTOList
     * @return
     */
    public static StockRangeDTO getMatchLowRangeByDateRange(StockDayData stockDayData,
        List<StockRangeDTO> stockRangeDTOList, BigDecimal highScope, BigDecimal lowScope) {
        String date = stockDayData.getDate();
        Date currentDate = DateUtil.parseDate(date);
        stockRangeDTOList = getRangeListByDateRange(stockRangeDTOList, stockDayData);
        if (CollectionUtils.isEmpty(stockRangeDTOList)) {
            return null;
        }

        StockRangeDTO lowRange = null;
        BigDecimal minPrice = null;
        StockRangeDTO minRange = null;
        for (StockRangeDTO stockRangeDTO : stockRangeDTOList) {
            if (RangeTypeEnums.UP.equalsCode(stockRangeDTO.getRangeType())) {
                continue;
            }
            //默认设置第一个最低价
            if (Objects.isNull(minRange)) {
                minPrice = stockRangeDTO.getLowPrice();
                minRange = stockRangeDTO;
            }
            Date endDate = DateUtil.parseDate(stockRangeDTO.getEndDate());
            //低价波段在20天之内,当成未匹配
            if (currentDate.getTime() - endDate.getTime() <= 86400000 * 20) {
                continue;
            }
            if (BigDecimalUtils.isLt(stockRangeDTO.getLowPrice(), minPrice)) {
                minPrice = stockRangeDTO.getLowPrice();
                minRange = stockRangeDTO;
            }
            BigDecimal rate = BigDecimalUtils.subStractAndDividePrecent(stockRangeDTO.getLowPrice(),
                stockDayData.getClosePrice()).abs();
            if (BigDecimalUtils.isLe(rate, highScope) && BigDecimalUtils.isGe(rate, lowScope)) {
                lowRange = stockRangeDTO;
            }
        }
        if (Objects.isNull(lowRange)) {
            return null;
        }
        if (Objects.isNull(minRange)) {
            minRange = lowRange;
        }
        //最低价比匹配波段还低5%以上,当成未匹配
        BigDecimal rate = BigDecimalUtils.subStractAndDividePrecent(lowRange.getLowPrice(), minRange.getLowPrice());
        if (BigDecimalUtils.isGt(rate, new BigDecimal(10))) {
            return null;
        }

        return lowRange;
    }

    public static List<StockRangeDTO> getRangeListByBeginAndEnd(List<StockDayData> stockDayDataList,
        String beginDate, String endDate) {
        return getRangeListByBeginAndEnd(stockDayDataList, MIN_RANGE_PRICE_SCOPE, beginDate, endDate);
    }

    public static List<StockRangeDTO> getRangeListByBeginAndEnd(List<StockDayData> stockDayDataList,
        BigDecimal rangePriceScope,
        String beginDate, String endDate) {
        List<StockRangeDTO> stockRangeDTOList = calculateStockRange(stockDayDataList, rangePriceScope);
        return getRangeListByDateRange(stockRangeDTOList, beginDate, endDate);
    }

    public static List<StockRangeDTO> getRangeListByDateRange(List<StockDayData> stockDayDataList,
        BigDecimal rangePriceScope, String endDateStr) {
        List<StockRangeDTO> stockRangeDTOList = calculateStockRange(stockDayDataList, rangePriceScope);
        String beginDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.parseDate(endDateStr), -450));
        return getRangeListByDateRange(stockRangeDTOList, beginDate, endDateStr);
    }

    public static List<StockRangeDTO> getRangeListByDateRange(List<StockRangeDTO> stockRangeDTOList,
        StockDayData stockDayData) {
        String endDateStr = stockDayData.getDate();
        Date endDate = DateUtil.parseDate(endDateStr);
        String beginDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.parseDate(endDateStr), -450));
        List<StockRangeDTO> rangeDTOList = getRangeListByDateRange(stockRangeDTOList, beginDate, endDateStr);
        if (CollectionUtils.isEmpty(rangeDTOList)) {
            return null;
        }
        StockRangeDTO lastRangeDTO = rangeDTOList.get(rangeDTOList.size() - 1);
        Date lastDate = DateUtil.parseDate(lastRangeDTO.getEndDate());
        if (lastDate.after(endDate)) {
            lastRangeDTO.setEndDate(endDateStr);
            if (RangeTypeEnums.DOWN.equalsCode(lastRangeDTO.getRangeType())) {
                lastRangeDTO.setLowPrice(stockDayData.getMinPrice());
            } else {
                lastRangeDTO.setHighPrice(stockDayData.getMaxPrice());
            }
        }
        return rangeDTOList;
    }

    public static List<StockRangeDTO> getRangeListByDateRange(List<StockRangeDTO> stockRangeDTOList,
        String beginDateStr, String endDateStr) {
        Date begin = DateUtil.parseDate(beginDateStr);
        Date end = DateUtil.parseDate(endDateStr);
        List<StockRangeDTO> rangeList = new ArrayList<>();
        for (StockRangeDTO stockRangeDTO : stockRangeDTOList) {
            Date beginDate = DateUtil.parseDate(stockRangeDTO.getBeginDate());
            Date endDate = DateUtil.parseDate(stockRangeDTO.getEndDate());
            // 如果一个时间段的开始时间晚于另一个时间段的结束时间，则两者无交集
            if (endDate.before(begin) || end.before(beginDate)) {
                continue;
            }
            rangeList.add(stockRangeDTO);

        }
        return rangeList;
    }

    /**
     * 统计波段前三的高低点信息
     *
     * @param stockRangeDTOList
     * @return
     */
    public static StockRangeStatistic statisticRange(List<StockRangeDTO> stockRangeDTOList) {
        List<StockRangeDTO> list = stockRangeDTOList.stream()
            .filter(stockRangeDTO -> StringUtils.equals(stockRangeDTO.getRangeType(), RangeTypeEnums.UP.getCode()))
            .collect(Collectors.toList());
        Collections.sort(list, (o1, o2) -> BigDecimalUtils.isGe(o1.getLowPrice(), o2.getLowPrice()) ? 1 : -1);
        StockRangeStatistic stockRangeStatistic = new StockRangeStatistic();
        stockRangeStatistic.setHighRange(list.get(0));
        stockRangeStatistic.setSecondHighRange(list.get(1));
        stockRangeStatistic.setThirdHighRange(list.get(2));
        stockRangeStatistic.setLowRange(list.get(list.size() - 1));
        stockRangeStatistic.setSecondLowRange(list.get(list.size() - 2));
        stockRangeStatistic.setThirdLowRange(list.get(list.size() - 3));
        return stockRangeStatistic;
    }

    /**
     * 查询股价是否进入低价区间
     *
     * @param closePrice
     * @param stockRangeDTOList
     * @param yearDate
     * @return
     */
    public static StockRangeApproximateData findApproximateDataWithStockRangeList(BigDecimal closePrice,
        List<StockRangeDTO> stockRangeDTOList, String yearDate) {
        List<StockRangeApproximateData> stockRangeApproximateDataList = reorganizeStockRangeList(stockRangeDTOList,
            yearDate);
        if (CollectionUtils.isEmpty(stockRangeApproximateDataList)) {
            return null;
        }
        //超过2个波段类似的，就取价格最低那2个波段
        if (stockRangeApproximateDataList.size() > 2) {
            stockRangeApproximateDataList = stockRangeApproximateDataList.subList(0, 2);
        }
        for (StockRangeApproximateData data : stockRangeApproximateDataList) {
            if (BigDecimalUtils.isLe(closePrice, data.getAvgPrice()) && BigDecimalUtils.isGe(closePrice,
                data.getLowPrice())) {
                return data;
            }
        }
        return null;
    }

    /**
     * 查询股价是否进入高价区间
     *
     * @param closePrice
     * @param stockRangeDTOList
     * @param yearDate
     * @return
     */
    public static StockRangeApproximateData findHighApproximateDataWithStockRangeList(BigDecimal closePrice,
        List<StockRangeDTO> stockRangeDTOList, String yearDate) {
        List<StockRangeApproximateData> stockRangeApproximateDataList = reorganizeStockRangeList(stockRangeDTOList,
            yearDate);
        if (CollectionUtils.isEmpty(stockRangeApproximateDataList)) {
            return null;
        }
        //超过2个波段类似的，就取价格最高那2个波段
        if (stockRangeApproximateDataList.size() > 2) {
            stockRangeApproximateDataList = stockRangeApproximateDataList.subList(
                stockRangeApproximateDataList.size() - 2, stockRangeApproximateDataList.size());
        }
        for (StockRangeApproximateData data : stockRangeApproximateDataList) {
            if (BigDecimalUtils.isGe(closePrice, data.getAvgPrice()) && BigDecimalUtils.isLe(closePrice,
                data.getHighPrice())) {
                return data;
            }
        }
        return null;
    }

    /**
     * 整理波段信息
     *
     * @return
     */
    public static List<StockRangeApproximateData> reorganizeStockRangeList(List<StockRangeDTO> stockRangeDTOList,
        String yearDate) {
        if (StringUtils.isNotBlank(yearDate)) {
            Date end = DateUtil.parseDate(yearDate);
            //5年之内
            Date begin = DateUtil.offsetMonth(end, -60);
            stockRangeDTOList = stockRangeDTOList.stream()
                .filter(stockRangeDTO -> {
                    Date rangeDate = DateUtil.parseDate(stockRangeDTO.getEndDate());
                    return rangeDate.after(begin) && rangeDate.before(end);
                })
                .collect(Collectors.toList());
        }
        //按价格排序
        List<StockRangeDTO> list = stockRangeDTOList.stream()
            .filter(stockRangeDTO -> StringUtils.equals(stockRangeDTO.getRangeType(), RangeTypeEnums.UP.getCode()))
            .collect(Collectors.toList());
        Collections.sort(list, (o1, o2) -> BigDecimalUtils.isGe(o1.getLowPrice(), o2.getLowPrice()) ? 1 : -1);
        Map<String, StockRangeApproximateData> rangeApproximateDataMap = new LinkedHashMap<>();
        List<StockRangeApproximateData> stockRangeApproximateDataList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            StockRangeDTO stockRangeDTO = list.get(i);
            List<StockRangeDTO> subList = getMatchRangeList(stockRangeDTO, list, i);
            StockRangeApproximateData approximateData = new StockRangeApproximateData(subList);
            rangeApproximateDataMap.put(BigDecimalUtils.toString(stockRangeDTO.getLowPrice(), 2), approximateData);
            stockRangeApproximateDataList.add(approximateData);
        }
        List<StockRangeApproximateData> rangeApproximateList = new ArrayList<>();
        String nextPrice = null;
        for (Entry<String, StockRangeApproximateData> entry : rangeApproximateDataMap.entrySet()) {
            String price = entry.getKey();
            if (StringUtils.isNotBlank(nextPrice) && !StringUtils.equals(price, nextPrice)) {
                continue;
            }
            StockRangeApproximateData approximateData = entry.getValue();
            int count = approximateData.getCount();
            //波段重叠<2次，波段无价值,跳过
            if (count < 2) {
                nextPrice = null;
                continue;
            }
            nextPrice = BigDecimalUtils.toString(approximateData.getHighPrice(), 2);
            StockRangeApproximateData nextApproximateData = rangeApproximateDataMap.get(nextPrice);
            if (Objects.isNull(nextApproximateData)) {
                continue;
            } else if (nextApproximateData.getCount() <= 2) {
                //log.debug("聚合5点波段为{}-{},次数为:{}", approximateData.getLowPrice(), approximateData.getHighPrice(),
                //    approximateData.getCount());
                approximateData.setRangeList(
                    BeanConvertUtils.convertList(approximateData.getRangeList(), StockRangeDTO.class));
                rangeApproximateList.add(approximateData);
            } else {
                count += nextApproximateData.getCount();
                //log.debug("聚合10点波段为{}-{},次数为:{}", approximateData.getLowPrice(), nextApproximateData.getHighPrice(),
                //    count);
                List<StockRangeDTO> rangeList = nextApproximateData.getRangeList();
                rangeList.remove(0);
                approximateData.getRangeList().addAll(rangeList);
                approximateData.setRangeList(
                    BeanConvertUtils.convertList(approximateData.getRangeList(), StockRangeDTO.class));
                approximateData.init();
                rangeApproximateList.add(approximateData);
                nextPrice = BigDecimalUtils.toString(nextApproximateData.getHighPrice(), 2);
            }
        }
        return rangeApproximateList;
    }

    private static List<StockRangeDTO> getMatchRangeList(StockRangeDTO stockRangeDTO, List<StockRangeDTO> list,
        int index) {
        List<StockRangeDTO> stockRangeDTOList = new ArrayList<>();
        stockRangeDTOList.add(stockRangeDTO);
        BigDecimal price = stockRangeDTO.getLowPrice().multiply(new BigDecimal(1.05));
        for (int i = index + 1; i < list.size(); i++) {
            StockRangeDTO rangeDTO = list.get(i);
            if (BigDecimalUtils.isLe(rangeDTO.getLowPrice(), price)) {
                stockRangeDTOList.add(rangeDTO);
            }
        }
        return stockRangeDTOList;
    }

    /**
     * 找到这一段中的顶点或者低点
     *
     * @param direction
     * @param stockDayDataList
     * @param startIndex
     * @param endIndex
     * @return
     */
    private static int getChangeIndex(String direction, List<StockDayData> stockDayDataList, int startIndex,
        int endIndex) {

        List<StockDayData> subList = stockDayDataList.subList(startIndex, endIndex);
        StockDayData startData = stockDayDataList.get(startIndex);
        BigDecimal startPrice = startData.getClosePrice();
        BigDecimal maxRange = BigDecimal.ZERO;
        int index = 0;
        for (int i = 0; i < subList.size(); i++) {
            StockDayData stockDayData = subList.get(i);
            if (StringUtils.equals(direction, "up")) {
                BigDecimal range = stockDayData.getMaxPrice().subtract(startPrice);
                if (BigDecimalUtils.isGt(range, maxRange)) {
                    maxRange = range;
                    index = i;
                }
            } else {
                BigDecimal range = startPrice.subtract(stockDayData.getMinPrice());
                if (BigDecimalUtils.isGt(range, maxRange)) {
                    maxRange = range;
                    index = i;
                }
            }
        }

        return startIndex + index;
    }

    private static StockDirectionData getDirectionData(StockDayData stockDayData, List<StockDayData> subList,
        BigDecimal rangePriceScope) {
        if (CollectionUtils.isEmpty(subList)) {
            return null;
        }
        BigDecimal hundred = new BigDecimal(100);
        BigDecimal temp = BigDecimalUtils.subStractAndDividePrecent(hundred, hundred.add(rangePriceScope));
        BigDecimal downRangePriceScope = hundred.subtract(temp);
        //BigDecimal highPrice = BigDecimalUtils.isGe(stockDayData.getRate(), BigDecimal.ZERO)
        //    ? stockDayData.getClosePrice() : stockDayData.getOpenPrice();
        //BigDecimal lowPrice = BigDecimalUtils.isGe(stockDayData.getRate(), BigDecimal.ZERO)
        //    ? stockDayData.getOpenPrice() : stockDayData.getClosePrice();
        BigDecimal highPrice = stockDayData.getMaxPrice();
        BigDecimal lowPrice = stockDayData.getMinPrice();
        int highIndex = 0;
        int lowIndex = 0;
        for (int i = 0; i < subList.size(); i++) {
            StockDayData data = subList.get(i);
            //BigDecimal dataMaxPrice = BigDecimalUtils.isGe(data.getRate(), BigDecimal.ZERO) ? data.getClosePrice()
            //    : data.getOpenPrice();
            //BigDecimal dataMinPrice = BigDecimalUtils.isGe(data.getRate(), BigDecimal.ZERO) ? data.getOpenPrice()
            //    : data.getClosePrice();
            BigDecimal dataMaxPrice = data.getMaxPrice();
            BigDecimal dataMinPrice = data.getMinPrice();
            if (BigDecimalUtils.isGt(dataMaxPrice, highPrice)) {
                highPrice = dataMaxPrice;
                highIndex = i;
            }
            if (BigDecimalUtils.isLt(dataMinPrice, lowPrice)) {
                lowPrice = dataMinPrice;
                lowIndex = i;
            }
            if (i < 1) {
                continue;
            }
            //波段内最高价和最低价差价超过范围，即形成波段
            BigDecimal rate = BigDecimalUtils.subStractAndDividePrecent(highPrice, lowPrice);
            if (BigDecimalUtils.isGe(rate, rangePriceScope)) {
                StockDirectionData stockDirectionData = new StockDirectionData();
                stockDirectionData.setStockDayData(data);
                String direction = highIndex >= lowIndex ? "up" : "down";
                stockDirectionData.setDirection(direction);
                stockDirectionData.setIndex(i);
                //后面是高价，中间即为低价;后面是低价,中间为高价
                int middleIndex = highIndex >= lowIndex ? lowIndex : highIndex;
                stockDirectionData.setMiddleIndex(middleIndex);
                return stockDirectionData;
            }
        }
        StockDirectionData stockDirectionData = new StockDirectionData();
        stockDirectionData.setStockDayData(subList.get(subList.size() - 1));
        String direction = BigDecimalUtils.isGt(stockDirectionData.getStockDayData().getClosePrice(),
            stockDayData.getClosePrice()) ? "up" : "down";
        stockDirectionData.setDirection(direction);
        stockDirectionData.setIndex(subList.size() - 1);
        stockDirectionData.setMiddleIndex(stockDirectionData.getIndex());
        return stockDirectionData;
    }

    private static void calculateRangeHoldDay(List<StockRangeDTO> result, List<StockDayData> stockDayDataList) {
        for (StockRangeDTO rangeDTO : result) {
            List<StockDayData> subList = StockUtils.getStockDayDataListByDateRange(stockDayDataList,
                rangeDTO.getBeginDate(), rangeDTO.getEndDate());
            rangeDTO.setHoldDay(subList.size() + 1);
        }
    }

    private static void addLatestRange(List<StockRangeDTO> result, List<StockDayData> stockDayDataList) {
        StockRangeDTO stockRangeDTO = result.get(result.size() - 1);
        StockDayData stockDayData = stockDayDataList.get(stockDayDataList.size() - 1);
        //最后的波段向下
        if (RangeTypeEnums.DOWN.equalsCode(stockRangeDTO.getRangeType())) {
            //后续价格也向下,更新向下波段
            if (BigDecimalUtils.isLe(stockDayData.getClosePrice(), stockRangeDTO.getLowPrice())) {
                stockRangeDTO.setEndDate(stockDayData.getDate());
                stockRangeDTO.setLowPrice(stockDayData.getClosePrice());
                stockRangeDTO.setRate(
                    BigDecimalUtils.subStractAndDividePrecent(stockRangeDTO.getLowPrice(), stockRangeDTO.getHighPrice())
                        .abs());
            } else {
                //后续价格向上,新增波段
                StockRangeDTO rangeDTO = new StockRangeDTO();
                rangeDTO.setRangeType(RangeTypeEnums.UP.getCode());
                rangeDTO.setCode(stockRangeDTO.getCode());
                rangeDTO.setBeginDate(stockRangeDTO.getEndDate());
                rangeDTO.setLowPrice(stockRangeDTO.getLowPrice());
                rangeDTO.setEndDate(stockDayData.getDate());
                rangeDTO.setHighPrice(stockDayData.getClosePrice());
                rangeDTO.setRate(BigDecimalUtils.subStractAndDividePrecent(stockDayData.getClosePrice(),
                    stockRangeDTO.getLowPrice()));
                result.add(rangeDTO);
            }
        } else if (RangeTypeEnums.UP.equalsCode(stockRangeDTO.getRangeType())) {
            //后续价格也向上,更新向上波段
            if (BigDecimalUtils.isGe(stockDayData.getClosePrice(), stockRangeDTO.getHighPrice())) {
                stockRangeDTO.setEndDate(stockDayData.getDate());
                stockRangeDTO.setHighPrice(stockDayData.getClosePrice());
                stockRangeDTO.setRate(
                    BigDecimalUtils.subStractAndDividePrecent(stockRangeDTO.getHighPrice(),
                        stockRangeDTO.getLowPrice()));
            } else {
                //后续价格向下,新增波段
                StockRangeDTO rangeDTO = new StockRangeDTO();
                rangeDTO.setRangeType(RangeTypeEnums.DOWN.getCode());
                rangeDTO.setCode(stockRangeDTO.getCode());
                rangeDTO.setBeginDate(stockRangeDTO.getEndDate());
                rangeDTO.setLowPrice(stockDayData.getClosePrice());
                rangeDTO.setEndDate(stockDayData.getDate());
                rangeDTO.setHighPrice(stockRangeDTO.getHighPrice());
                rangeDTO.setRate(BigDecimalUtils.subStractAndDividePrecent(stockDayData.getClosePrice(),
                    stockRangeDTO.getHighPrice()));
                result.add(rangeDTO);
            }
        }

    }

    public static int cacullateStockImage(List<StockDayData> stockDayDataList, StockDayData data) {
        List<Integer> periods = Lists.newArrayList(120, 60, 30, 20, 10);
        if (stockDayDataList.size() < 120) {
            return -1;
        }
        String date = data.getDate();
        List<StockDayData> periodDataList = new ArrayList<>();
        for (Integer period : periods) {
            StockDayData stockDayData = StockUtils.getStockDayDataBeforeDate(stockDayDataList, date, period);
            periodDataList.add(stockDayData);
        }
        periodDataList.add(data);
        List<StockDayData> imageDataList = new ArrayList<>();
        for (int i = 0; i < periodDataList.size() - 1; i++) {
            StockDayData periodData = periodDataList.get(i);
            if (Objects.isNull(periodData)) {
                break;
            }
            BigDecimal periodPrice = periodData.getClosePrice();
            List<StockDayData> subList = StockUtils.getStockDayDataListByDateRange(stockDayDataList,
                periodData.getDate(), periodDataList.get(i + 1).getDate());
            StockDayData lowData = StockUtils.getMinPriceData(subList);
            StockDayData highData = StockUtils.getMaxPriceData(subList);
            BigDecimal lowPrice = lowData.getClosePrice();
            BigDecimal highPrice = highData.getClosePrice();
            //最低价比日期价还高,说明是上涨区间，取最高价
            if (BigDecimalUtils.isGe(lowPrice, periodPrice)) {
                imageDataList.add(highData);
            } else if (BigDecimalUtils.isLe(highPrice, periodPrice)) {
                //最高价比日期价还低,说明是下跌区间，取最低价
                imageDataList.add(lowData);
            } else {
                BigDecimal highRate = BigDecimalUtils.subStractAndDividePrecent(highPrice, periodPrice);
                BigDecimal lowRate = BigDecimalUtils.subStractAndDividePrecent(periodPrice, lowPrice);
                if (BigDecimalUtils.isGt(highRate, lowRate)) {
                    imageDataList.add(highData);
                } else {
                    imageDataList.add(lowData);
                }
            }
        }
        if(CollectionUtils.isEmpty(imageDataList)){
            return -1;
        }
        Map<BigDecimal, StockDayData> dataMap = new HashMap<>();
        List<BigDecimal> priceList = new ArrayList<>();
        for (StockDayData imageData : imageDataList) {
            dataMap.put(imageData.getClosePrice(), imageData);
            priceList.add(imageData.getClosePrice());
        }
        Collections.sort(priceList);
        int value = 1;
        BigDecimal compareRate = new BigDecimal(15);
        BigDecimal tempPrice = priceList.get(0);
        Map<BigDecimal, Integer> valueMap = new HashMap<>();
        for (int i = 0; i < priceList.size(); i++) {
            BigDecimal price = priceList.get(i);
            BigDecimal rate = BigDecimalUtils.subStractAndDividePrecent(price, tempPrice);
            if (BigDecimalUtils.isGt(rate, compareRate)) {
                value++;
                tempPrice = price;
            }
            valueMap.put(price, value);
        }
        String s = "";
        for (StockDayData imageData : imageDataList) {
            int v = valueMap.get(imageData.getClosePrice());
            s += v;
        }
        return Integer.parseInt(s);
    }

    @Data
    public static class StockDirectionData {
        private String direction;

        private StockDayData stockDayData;

        private int index;

        private int middleIndex;

    }

}

